package com.vincent.template.commons.validation.constraints;

import com.vincent.template.commons.validation.validators.FieldCompareValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 判断两个字段的值是否符合预期的比较规则（字段类型必须一致）
 * @author Vincent Wang
 * @date 2020/11/9 16:25
 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Repeatable(ReplicateFieldCompare.class)
@Constraint(validatedBy = {FieldCompareValidator.class})
public @interface FieldCompare {

    /** 主动比较方字段 */
    String targetField();

    /** 被比较基准字段 */
    String baseField();

    /** 比较条件（关系式） */
    Condition condition();

    /** 字段值为空时的处理方式 */
    EmptyCase emptyCase() default EmptyCase.SKIP_CHECK;

    String message() default "{targetField}必须${condition.description}{baseField}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * 字段值之间的关系
     */
    enum Condition {
        /** 等于 */
        EQUALS(result -> result == 0, "等于"),
        /** 不等于 */
        NOT_EQUALS(result -> result != 0, "不等于"),
        /** 大于 */
        GREATER(result -> result > 0, "大于"),
        /** 大于等于 */
        GREATER_OR_EQUALS(result -> result >= 0, "大于或等于"),
        /** 小于 */
        LESSER(result -> result < 0, "小于"),
        /** 小于等于 */
        LESSER_OR_EQUALS(result -> result <= 0, "小于或等于");

        private final Express express;

        private final String description;

        Condition(Express express, String description) {
            this.express = express;
            this.description = description;
        }

        public Express getExpress() {
            return express;
        }

        public String getDescription() {
            return description;
        }
    }

    interface Express {
        /**
         * 判断方式
         * @param result
         * @return
         */
        boolean decide(int result);
    }

    /**
     * 出现字段值为空时的处理规则
     */
    enum EmptyCase {
        /** 抛异常 */
        THROW_EXCEPTION,
        /** 跳过check，结果直接返回true */
        SKIP_CHECK,
        /** 空值作为更小值 */
        AS_LESSER,
        /** 空值作为更大值 */
        AS_GREATER
    }
}
